/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package jserver;

/**
 *
 * @author famiglia
 */


import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Server extends Thread {

    private ArrayList<Connessione> clients;//Array List contente le socket dei vari clients
    private ArrayList<Utente> utentiList;//Array List contente i vari utenti attivi sul server
    private boolean inizClient;//variabile che indica lo stato di inizializzazione di un client

    private class Connessione extends Thread {
        private Socket sock;
        private BufferedReader reader;//Flusso di input
        private DataOutputStream printer;//Flusso di output

        public Connessione(Socket clientAccept) {
            this.sock=clientAccept;
            try {
                // Apre i canali I/O
                this.reader = new BufferedReader(new InputStreamReader(this.sock.getInputStream()));
                this.printer= new DataOutputStream(this.sock.getOutputStream());
            } catch (IOException ex) {
            }
           
        }

        public String readLine(){//Legge una linea dal canale di Input
            String line=null;
            try {
                line = this.reader.readLine();
            } catch (IOException ex) {
            }
            return line;
        }

        public void writeLine(String line){//Scrive una linea sul canale di Output
            try {
                this.printer.writeBytes(line + "\n");
            } catch (IOException ex) {
            }
        }

        @Override
        public void run() {
            String line=null;
            int tipoMex;
            int idCanc = -1;
             while(!inizClient)
            {
                //rimane in attesa della fine delle procedure di inizializzazione del client
            }
            while((line=this.readLine())!=null){//legge un messaggio del tipo TipoMex|IdMittente|IdRicevente|Messaggio
                String [] temp = null;
                temp = line.split("\\|");//Le parti del messaggio vengono divise
                tipoMex = Integer.parseInt(temp[0]);
                if(tipoMex==-1)//Caso messaggio
                {
                    int i = Integer.parseInt(temp[2]);//chi deve ricevere il msg
                    clients.get(i).writeLine(temp[0]+"|" + temp[1]+ "|" + temp[3]);//invio msg
                }
                else if(tipoMex ==-2)//Caso utente disconnesso
                {
                   
                    for(int i=0;i<utentiList.size();i++)//Elimina l'utente disconnesso da utentiList
                    {
                        if(utentiList.get(i).getId()== Integer.parseInt(temp[1]))
                        {
                            idCanc = i;
                            utentiList.remove(i);
                            break;
                        }

                    }
                    if(!utentiList.isEmpty())//Aggiorna gli id della utentiList
                    {
                        for(int j=idCanc; j<utentiList.size();j++)
                        {
                            int newid = (utentiList.get(j).getId())-1;
                            utentiList.get(j).setId(newid);
                        }
                    }
                    for(int i=0; i<clients.size();i++){//Elimina la socket relativa all'utente
                        if(i==(Integer.parseInt(temp[1])))
                        {
                            clients.remove(i);
                            break;
                        }

                    }
                    if(clients.size()>0)//Invia ai client restanti che l'utente si è disconnesso
                    {
                        for(int i=0; i<clients.size(); i++){
                            clients.get(i).writeLine(temp[0]+"|" + temp[1]+ "|CANC");
                        }
                        
                    }
                }
                else if(tipoMex ==-3)//Caso utente connesso
                {
                    for(int i=0; i<clients.size(); i++){//Invia a tutti i clients tranne se stesso che un nuovo utente è connesso
                        if(i!=Integer.parseInt(temp[1]))
                        clients.get(i).writeLine(temp[0]+"|" + temp[1]+ "|"+ temp[3]);
                    }
                }
                

            }
        }
    }

    public Server() {
        this.clients = new ArrayList<Connessione>();//Inizializza clients
        this.utentiList = new ArrayList<Utente>();//Inizializza utentiList
    }

    @Override
    public void run() {
        String linea = "";
        boolean nomeImpostato;
        try {
            ServerSocket server = new ServerSocket(2223);
            while (true) {
                nomeImpostato=false;
                Socket clientAccept = server.accept();//Resta in attesa di un nuovo client
                Connessione client= new Connessione(clientAccept);
                inizClient = false;//Inizia la fase di inizializzazzione client
                client.start();
                this.clients.add(client);//Aggiunge alla lista clients un nuovo client
                int id = this.clients.size()-1;//Genera un id per il client
                linea = client.readLine();//Legge dal server il nome utente desiderato
                if(utentiList.isEmpty())//Inizio fase creazione nuovo utente
                {
                    this.utentiList.add(new Utente(id,linea));
                    nomeImpostato = true;
                }
                else
                {
                    for(int i=0;i<utentiList.size();i++)
                    {
                        if(linea.equals(utentiList.get(i).getNome()))//Controlla che il nome non vi sia già
                        {
                            linea = linea + id;//Modifica il nome utente desiderato con il nome utente finale
                            this.utentiList.add(new Utente(id,linea));
                            nomeImpostato = true;
                            break;
                        }
                    }
                }
                if(!nomeImpostato)//Fine fase creazione nuovo utente
                {
                    nomeImpostato = true;
                    this.utentiList.add(new Utente(id,linea));
                }
                String nome = linea;
                if(utentiList.size()==1)//Crea il messaggio tipo -3 con la lista utenti collegati per l'id appena collegato
                {
                    linea = "-3|-1|";
                    linea = linea + utentiList.get(0).getId() + ":" + utentiList.get(0).getNome();
                }
                else
                {
                    linea = "-3|-1|";
                    for(int i=0;i<utentiList.size();i++){
                    linea = linea + utentiList.get(i).getId() + ":" + utentiList.get(i).getNome() + ",";
                    }
                }
                client.writeLine(""+id);//Invia l'id al nuovo client
                client.writeLine(nome);//Invia il nome al nuovo client
                client.writeLine(linea);//Invia la lista utenti collegati al nuovo client
                inizClient = true;//Finisce la fase di inizializzazione client
            }
        } catch (IOException ex) {
            Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
        }

    }


    public static void main(String[] args) {
        new Server().start();
    }
}
